/**
 * 上海中赢金融信息服务有限公司
 * Copyright (c) 2016-2026 hmc,Inc.All Rights Reserved.
 */
package com.sys.midware.rdb.datasource;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Map.Entry;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSource;
import com.sys.midware.assist.utils.string.StringUtil;
import com.sys.midware.logger.Logger;
import com.sys.midware.logger.LoggerFactory;
import com.sys.midware.rdb.config.RDBConfig;
import com.sys.midware.rdb.config.RDBConfigUtil;
import com.sys.midware.rdb.dbRouter.DBClusterRouter;
import com.sys.midware.rdb.dbRouter.DBClusterRouter.RouterStrategy;
import com.sys.midware.rdb.exception.RDBException;

/**
 * 该类为对外提供的datasource，可以提供给ioc容器，或者在程序中使用
 * 
 * @author mobing@b5m.com
 * @see com.BDataSource.ocean.datasource.OceanDataSource
 * @version V0.0.1-SNAPSHOT, 2015-08-13上午9:47:27
 * @description
 * 
 */
public class BDataSource extends AbstractDataSource {

    private final static Logger LOG = LoggerFactory.getLogger(BDataSource.class);

    /**
     * 构造方法 如果是spring，则会先调用该构造。 如果是编程，则需要为path赋值
     */
    public BDataSource() {
    }

    /**
     * 构造方法 如果是spring，则会先调用该构造。 如果是编程，则需要为path赋值
     */
    public BDataSource(String path) {
        this.path = path;
    }
    
    /**
     * 构造方法 如果是spring，则会先调用该构造。 如果是编程，则需要为path赋值
     */
    public BDataSource(String path,String nodeKey) {
        this.path = path;
        this.nodeKey = nodeKey;
    }

    /**
     * 数据源节点Map key：数据源节点key value：数据源节点
     */
    // private Map<String, DataSource> dataSourcesNodeMap;

    /**
     * 默认数据源节点
     */
    private DataSource defaultDataSourceNode;

    /**
     * 配置文件路径，可以编程式获取也可以从spring中注入进来
     */
    private String path;

    /**
     * 是否已经初始化
     */
    private boolean inited;

    /**
     * 数据源节点
     */
    private String nodeKey;

//    private static RDBConfig rdbConfig = null;

    /**
     * 用来从配置文件中初始化数据源
     */
    public synchronized void init() {
        if (inited) {
            return;
        }
        Map<String, RDBConfig> rdbConfigMap = RDBConfigUtil.initConfig();
        //根据配置转成map类型的datasource
        BDataSourceUtil.setNodeDataSourceMap(rdbConfigMap);
        // 如果
        if (StringUtil.isNotEmpty(nodeKey)) {
            BDataSourceUtil.setValidDataSource(nodeKey);
        } else {
            boolean selected= false;
            // 如果没有传nodename，则随机取一个RDB配置
            for (Entry<String, RDBConfig> map : rdbConfigMap.entrySet()) {
                //如果设置了默认属性，则走默认的数据源，否则随机选取一个数据
                RDBConfig rdbConfig=  map.getValue();
                if(rdbConfig!=null){
                    if("true".equalsIgnoreCase(rdbConfig.getNodeDefault())){
                        if (BDataSourceUtil.setValidDataSource(map.getKey())) {
                            selected=true;
                            break;
                        }
                    }
                }
            }
            //如果未设置默认数据源，则随机选取
            if(!selected){
                // 如果没有传nodename，则随机取一个RDB配置
                for (Entry<String, RDBConfig> map : rdbConfigMap.entrySet()) {
                    if (BDataSourceUtil.setValidDataSource(map.getKey())) {
                        break;
                    }
                }
            }
     

        }

        defaultDataSourceNode = DataSourceHolder.get();
        LOG.debug("默认数据源" + defaultDataSourceNode);
        inited = true;
        // 如果默认数据源为空，则抛异常
        if (defaultDataSourceNode == null) {
            throw new RDBException("未获取到默认数据源!");
        }
    }

    /**
     * 回收资源, 将所有连接关闭
     */
    public synchronized void close() {
        LOG.info("开始连接池回收...");
        Map<String, DataSource> dataSources = DataSourceMapHolder.get();
        if (dataSources != null && !dataSources.isEmpty()) {
            for (Map.Entry<String, DataSource> entry : DataSourceMapHolder.get().entrySet()) {
                try {
                    DataSource node = entry.getValue();
                    DruidDataSource dds = (DruidDataSource) node;
                    if (dds != null) {
                        LOG.info("开始关闭数据源节点: " + entry.getKey());
                        dds.close();
                    }
                } catch (Exception e) {
                    LOG.error(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 获取当前线程绑定的DataSource 1、如果未设置路由策略，则走默认数据源 2、如果已经设置了路由策略，则根据设置的路由策略来选择数据源,
     * 设置策略模式为不刷新
     */
    public DataSource getCurrentDataSource() {
        RouterStrategy strategy = DBClusterRouter.getRouterStrategy();
        LOG.info("获取当前线程数据源, 路由策略：" + (strategy == null ? "默认策略" : strategy));
        if (strategy == null) {
            LOG.debug("默认数据源为：" + defaultDataSourceNode);
            return defaultDataSourceNode;
        }
        return DataSourceHolder.get();
    }

    /**
     * 覆盖datasource的getConnection方法，以便持久层框架调用
     */
    public Connection getConnection() throws SQLException {
        return BDataSourceUtil.getValidConnection(getCurrentDataSource());
    }

    /**
     * 覆盖datasource的getConnection方法，以便持久层框架调用
     */
    @Deprecated
    public Connection getConnection(String username, String password) throws SQLException {
        DataSource ds = getCurrentDataSource();
        if (ds != null) {
            return ds.getConnection(username, password);
        }
        throw new NullPointerException("DataSource");
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    @Override
    public String toString() {
        return super.toString();
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    public String getNodeKey() {
        return nodeKey;
    }

    public void setNodeKey(String nodeKey) {
        this.nodeKey = nodeKey;
    }

}